Conversation
There was a problem hiding this comment.
Pull request overview
Adds a self-contained, single-file example market maker bot script to demonstrate basic cancel/replace quoting with inventory skew and risk guards using the current Decibel Python SDK APIs.
Changes:
- Introduces
examples/write/market_maker_bot.pyimplementing a periodic quoting loop (fetch state → cancel existing orders → place post-only bid/ask). - Adds CLI/env configuration for market/network/timing and basic risk limits (inventory and margin usage).
- Implements quote rounding to market tick/lot sizes via SDK utilities.
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
|
Addressed all three review points in commit d52a4f4:
Also added focused tests in
Validation run locally:
|
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 2 out of 2 changed files in this pull request and generated 2 comments.
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 2 out of 2 changed files in this pull request and generated 1 comment.
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 2 out of 2 changed files in this pull request and generated 2 comments.
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 2 out of 2 changed files in this pull request and generated 2 comments.
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 2 out of 2 changed files in this pull request and generated 1 comment.
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 2 out of 2 changed files in this pull request and generated 2 comments.
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 2 out of 2 changed files in this pull request and generated no new comments.
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
gregnazario
left a comment
There was a problem hiding this comment.
Seems fine, let's add documentation (saying what it does, since it is an example)
Document the market maker bot example with features, usage instructions, and configuration options. The bot demonstrates building a trading bot with inventory skew, margin management, and dry-run mode support. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 3 out of 3 changed files in this pull request and generated 3 comments.
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 3 out of 3 changed files in this pull request and generated 2 comments.
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| parser.add_argument("--spread", type=float, default=os.getenv("MM_SPREAD", "0.001")) | ||
| parser.add_argument( | ||
| "--order-size", | ||
| type=float, | ||
| default=os.getenv("MM_ORDER_SIZE", "0.001"), | ||
| ) |
There was a problem hiding this comment.
Numeric argparse options are using environment-variable strings as default values (e.g., default=os.getenv("MM_SPREAD", "0.001") with type=float). argparse does not apply the type converter to defaults, so these end up as str when the flag is omitted, and invalid env values (like MM_SPREAD=abc) won't trigger an argparse error (the included test expects a SystemExit(2)). Parse env vars into float/int before passing them as defaults (and call parser.error(...) on parse failure), and apply the same fix to all other numeric args here (order size, max inventory, skew, refresh/cooldown, cancel-resync, max-cycles).
| # Live mode (requires PRIVATE_KEY) | ||
| export PRIVATE_KEY="0x..." |
There was a problem hiding this comment.
README uses different PRIVATE_KEY formats: earlier it says your_private_key_hex, but this new section shows export PRIVATE_KEY="0x...". Please make the format consistent (or explicitly note that the 0x prefix is optional/accepted) to avoid copy/paste failures when calling PrivateKey.from_hex(...).
| # Live mode (requires PRIVATE_KEY) | |
| export PRIVATE_KEY="0x..." | |
| # Live mode (requires PRIVATE_KEY as a hex string; use the same format consistently. | |
| # If your setup uses PrivateKey.from_hex(...), omit the 0x prefix unless your parser explicitly accepts it.) | |
| export PRIVATE_KEY="your_private_key_hex" |
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 3 out of 3 changed files in this pull request and generated 1 comment.
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| if not math.isfinite(settings.max_inventory) or settings.max_inventory <= 0: | ||
| raise ValueError("max_inventory must be a finite value > 0; adjust --max-inventory") | ||
| if not math.isfinite(settings.max_margin_usage) or settings.max_margin_usage <= 0: | ||
| raise ValueError("max_margin_usage must be a finite value > 0; adjust --max-margin-usage") | ||
|
|
||
|
|
There was a problem hiding this comment.
_validate_settings() currently only checks max_inventory and max_margin_usage, but other user-controlled settings (e.g., spread, order_size, skew_per_unit, and the timing fields) can also be non-finite/negative and will only fail later inside _compute_quotes() or asyncio.sleep(). Consider validating all numeric settings up-front here (and producing a single actionable error) so the script fails fast before entering the cycle loop.
| if not math.isfinite(settings.max_inventory) or settings.max_inventory <= 0: | |
| raise ValueError("max_inventory must be a finite value > 0; adjust --max-inventory") | |
| if not math.isfinite(settings.max_margin_usage) or settings.max_margin_usage <= 0: | |
| raise ValueError("max_margin_usage must be a finite value > 0; adjust --max-margin-usage") | |
| errors: list[str] = [] | |
| finite_positive_fields = ( | |
| ("spread", settings.spread, "--spread"), | |
| ("order_size", settings.order_size, "--order-size"), | |
| ("max_inventory", settings.max_inventory, "--max-inventory"), | |
| ("skew_per_unit", settings.skew_per_unit, "--skew-per-unit"), | |
| ("max_margin_usage", settings.max_margin_usage, "--max-margin-usage"), | |
| ("refresh_interval_s", settings.refresh_interval_s, "--refresh-interval"), | |
| ("cooldown_s", settings.cooldown_s, "--cooldown"), | |
| ("cancel_resync_s", settings.cancel_resync_s, "--cancel-resync"), | |
| ) | |
| for field_name, value, flag in finite_positive_fields: | |
| if not math.isfinite(value) or value <= 0: | |
| errors.append(f"{field_name} must be a finite value > 0; adjust {flag}") | |
| if settings.max_cycles < 0: | |
| errors.append("max_cycles must be >= 0 (0 = run forever); adjust --max-cycles") | |
| if errors: | |
| raise ValueError("Invalid market maker settings: " + "; ".join(errors)) |
Summary
Add a new single-file market maker bot example under examples/write/market_maker_bot.py.
What is included
Why
This keeps the market-maker example self-contained and easy to run with the current Python SDK API surface.
Validation